好,今天不想開書店,改來開咖啡廳好了XD>
在一個村落裡,有一間很好喝的咖啡店,店內特色就是老闆的咖啡有精心搭配的特定甜點。每杯咖啡都可能搭配一種或多種甜點。店長希望顧客在點咖啡時,能先快速看到咖啡的資訊,而不需要浪費資源來加載所有甜點的資料。
下面分別來說說使用 Lazy Loading 和 Eager Loading 會產生什麼後續故事呢?
顧客進入咖啡店時,首先只看到咖啡的菜單。當顧客點了某杯咖啡並詢問搭配的甜點時,系統才去查詢該咖啡的甜點資訊。
這樣可以減少初始加載的數據,但在顧客每次詢問甜點時,系統都會增加一次查詢。
多對多的資料表 Coffee
跟 Dessert
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Coffee extends Model
{
/**
* Get the desserts that go with the coffee.
*/
public function desserts(): BelongsToMany
{
return $this->belongsToMany(Dessert::class);
}
}
使用 Lazy Loading 不會直接與咖啡有關的甜點資料,是先加載全部咖啡資料,容易導致查詢次數增加,當我們使用 $coffee->desserts
時,Laravel 會發出查詢請求來獲取該咖啡的甜點資料,這在有許多咖啡時會造成 N+1
查詢問題。
use App\Models\Coffee;
$coffees = Coffee::all(); // 這裡加載全部咖啡資料
foreach ($coffees as $coffee) {
echo $coffee->name . "\\n";
echo "搭配的甜點:\\n";
foreach ($coffee->desserts as $dessert) {
echo $dessert->name . "\\n"; // 每次訪問時都會查詢甜點
}
}
顧客一進咖啡店,店主就將所有咖啡和它們搭配的甜點一起展示出來。這樣在顧客查看咖啡時,也一次性加載了甜點資料,避免了多次查詢。
使用 Eager Loading 的 with
方法可以指定要預先載入哪些關係,with('desserts')
使 Laravel 一次性查詢所有咖啡及其甜點資料,從而提高效能,特別是在資料量大的時候。
// 使用 Eager Loading 加載咖啡及其甜點
$coffees = Coffee::with('desserts')->get(); // 一次加載所有咖啡和相關甜點
foreach ($coffees as $coffee) {
echo $coffee->name . "\\n";
echo "搭配的甜點:\\n";
foreach ($coffee->desserts as $dessert) {
echo $dessert->name . "\\n"; // 不會額外查詢
}
}
參考資料
踏著身心靈的塔羅腳步,轉向技術與邏輯的工程師之路,就藉由塔羅日抽來紀錄今日的學習與生活吧!
惡魔牌:惡魔牌象徵認真執著,Eager vs. Lazy 兩個皆有好壞,不需要堅持使用哪一種,可以在深入了解後,選擇自己需要的。
"Would you tell me, please, which way I ought to go from here?" said Alice.
"That depends a good deal on where you want to get to," said the Cat.
"I don't much care where--" said Alice.
"Then it doesn't matter which way you go," said the Cat.
"... so long as I get somewhere," Alice added as an explanation.
"Oh, you're sure to do that," said the Cat, "if you only walk long enough."「如果你不知道你要去哪裡,那麼現在你在哪裡一點都不重要。
只要你一直走,總會走到什麼地方的。」― Lewis Carroll, Alice in Wonderland